package com.icongyou.enterprise.talent_analysis.controller;

import com.icongyou.enterprise.talent_analysis.entity.dto.PortraitTemplateCreateRequest;
import com.icongyou.enterprise.talent_analysis.entity.dto.PortraitTemplateDTO;
import com.icongyou.enterprise.talent_analysis.entity.template.TemplateDimension;
import com.icongyou.enterprise.talent_analysis.service.PortraitTemplateService;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.*;

/**
 * 能力画像模板控制器测试
 */
@SpringBootTest
@AutoConfigureMockMvc
public class PortraitTemplateControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private PortraitTemplateService portraitTemplateService;

    @Test
    public void testCreateTemplate_success() throws Exception {
        PortraitTemplateDTO createdTemplate = createMockTemplateDTO("template001");
        
        Mockito.when(portraitTemplateService.createTemplate(any(PortraitTemplateCreateRequest.class)))
            .thenReturn(createdTemplate);

        String requestBody = "{"
            + "\"templateName\":\"技术岗位能力模板\","
            + "\"description\":\"用于评估技术岗位人才\","
            + "\"enterpriseId\":\"ent001\","
            + "\"createdBy\":\"hr001\","
            + "\"dimensions\":["
            + "  {\"code\":\"tech\",\"name\":\"技术能力\",\"description\":\"技术掌握程度\",\"weight\":0.2},"
            + "  {\"code\":\"problem\",\"name\":\"问题解决\",\"description\":\"解决问题能力\",\"weight\":0.2},"
            + "  {\"code\":\"learning\",\"name\":\"学习能力\",\"description\":\"学习新知识的能力\",\"weight\":0.2},"
            + "  {\"code\":\"teamwork\",\"name\":\"协作能力\",\"description\":\"团队合作能力\",\"weight\":0.1},"
            + "  {\"code\":\"communication\",\"name\":\"沟通能力\",\"description\":\"表达和交流能力\",\"weight\":0.15},"
            + "  {\"code\":\"execution\",\"name\":\"执行能力\",\"description\":\"任务执行能力\",\"weight\":0.15}"
            + "]"
            + "}";

        mockMvc.perform(post("/api/portrait/template")
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestBody))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.id").value("template001"))
            .andExpect(jsonPath("$.data.templateName").value("技术岗位能力模板"));

        Mockito.verify(portraitTemplateService).createTemplate(any(PortraitTemplateCreateRequest.class));
    }

    @Test
    public void testGetTemplate_success() throws Exception {
        String templateId = "template001";
        PortraitTemplateDTO template = createMockTemplateDTO(templateId);
        
        Mockito.when(portraitTemplateService.getTemplate(templateId))
            .thenReturn(template);

        mockMvc.perform(get("/api/portrait/template/{id}", templateId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.id").value(templateId))
            .andExpect(jsonPath("$.data.dimensions", hasSize(6)));

        Mockito.verify(portraitTemplateService).getTemplate(templateId);
    }

    @Test
    public void testGetTemplate_notFound() throws Exception {
        String templateId = "nonexistent";
        
        Mockito.when(portraitTemplateService.getTemplate(templateId))
            .thenReturn(null);

        mockMvc.perform(get("/api/portrait/template/{id}", templateId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data").isEmpty());
    }

    @Test
    public void testUpdateTemplate_success() throws Exception {
        String templateId = "template001";
        PortraitTemplateDTO updatedTemplate = createMockTemplateDTO(templateId);
        updatedTemplate.setTemplateName("更新后的模板名称");
        
        Mockito.when(portraitTemplateService.updateTemplate(eq(templateId), any(PortraitTemplateDTO.class)))
            .thenReturn(updatedTemplate);

        String requestBody = "{"
            + "\"templateName\":\"更新后的模板名称\","
            + "\"description\":\"更新后的描述\","
            + "\"dimensions\":["
            + "  {\"code\":\"tech\",\"name\":\"技术能力\",\"description\":\"技术掌握程度\",\"weight\":0.4},"
            + "  {\"code\":\"learning\",\"name\":\"学习能力\",\"description\":\"学习新知识的能力\",\"weight\":0.6}"
            + "]"
            + "}";

        mockMvc.perform(put("/api/portrait/template/{id}", templateId)
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestBody))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.templateName").value("更新后的模板名称"));

        Mockito.verify(portraitTemplateService).updateTemplate(eq(templateId), any(PortraitTemplateDTO.class));
    }

    @Test
    public void testListTemplates_allActive() throws Exception {
        String enterpriseId = "ent001";
        
        List<PortraitTemplateDTO> templates = Arrays.asList(
            createMockTemplateDTO("template001"),
            createMockTemplateDTO("template002"),
            createMockTemplateDTO("template003")
        );
        
        Mockito.when(portraitTemplateService.listTemplates(enterpriseId, true))
            .thenReturn(templates);

        mockMvc.perform(get("/api/portrait/templates")
                .param("enterpriseId", enterpriseId)
                .param("active", "true"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data", hasSize(3)))
            .andExpect(jsonPath("$.data[0].id").value("template001"));

        Mockito.verify(portraitTemplateService).listTemplates(enterpriseId, true);
    }

    @Test
    public void testListTemplates_all() throws Exception {
        String enterpriseId = "ent001";
        
        List<PortraitTemplateDTO> templates = Arrays.asList(
            createMockTemplateDTO("template001"),
            createMockTemplateDTO("template002")
        );
        
        Mockito.when(portraitTemplateService.listTemplates(enterpriseId, null))
            .thenReturn(templates);

        mockMvc.perform(get("/api/portrait/templates")
                .param("enterpriseId", enterpriseId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data", hasSize(2)));

        Mockito.verify(portraitTemplateService).listTemplates(enterpriseId, null);
    }

    @Test
    public void testListTemplates_empty() throws Exception {
        String enterpriseId = "ent001";
        
        Mockito.when(portraitTemplateService.listTemplates(enterpriseId, null))
            .thenReturn(new ArrayList<>());

        mockMvc.perform(get("/api/portrait/templates")
                .param("enterpriseId", enterpriseId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data", hasSize(0)));
    }

    @Test
    public void testListTemplates_serviceException() throws Exception {
        String enterpriseId = "ent001";
        
        Mockito.when(portraitTemplateService.listTemplates(anyString(), any()))
            .thenThrow(new RuntimeException("数据库查询失败"));

        mockMvc.perform(get("/api/portrait/templates")
                .param("enterpriseId", enterpriseId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(500))
            .andExpect(jsonPath("$.message", containsString("查询模板列表失败")));
    }

    @Test
    public void testDeleteTemplate_success() throws Exception {
        String templateId = "template001";
        
        Mockito.doNothing().when(portraitTemplateService).deleteTemplate(templateId);

        mockMvc.perform(delete("/api/portrait/template/{id}", templateId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200));

        Mockito.verify(portraitTemplateService).deleteTemplate(templateId);
    }

    @Test
    public void testDeleteTemplate_serviceException() throws Exception {
        String templateId = "template001";
        
        Mockito.doThrow(new RuntimeException("模板正在使用中"))
            .when(portraitTemplateService).deleteTemplate(templateId);

        mockMvc.perform(delete("/api/portrait/template/{id}", templateId))
            .andExpect(status().isOk());

        // 即使抛异常，Controller也会处理(根据实际实现)
        Mockito.verify(portraitTemplateService).deleteTemplate(templateId);
    }

    @Test
    public void testCreateTemplate_invalidRequest_missingFields() throws Exception {
        String requestBody = "{"
            + "\"templateName\":\"测试模板\""
            // 缺少必填字段
            + "}";

        mockMvc.perform(post("/api/portrait/template")
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestBody))
            .andExpect(status().isBadRequest()); // SpringBoot的验证会返回400

        // 验证注解会在Controller层被拦截，不会调用service
        Mockito.verify(portraitTemplateService, Mockito.never()).createTemplate(any(PortraitTemplateCreateRequest.class));
    }

    @Test
    public void testUpdateTemplate_withDifferentDimensionCount() throws Exception {
        String templateId = "template001";
        PortraitTemplateDTO updatedTemplate = createMockTemplateDTO(templateId);
        
        // 只保留2个维度
        updatedTemplate.getDimensions().subList(2, updatedTemplate.getDimensions().size()).clear();
        
        Mockito.when(portraitTemplateService.updateTemplate(eq(templateId), any(PortraitTemplateDTO.class)))
            .thenReturn(updatedTemplate);

        String requestBody = "{"
            + "\"templateName\":\"简化模板\","
            + "\"description\":\"只有2个维度\","
            + "\"dimensions\":["
            + "  {\"code\":\"tech\",\"name\":\"技术能力\",\"description\":\"技术掌握程度\",\"weight\":0.6},"
            + "  {\"code\":\"learning\",\"name\":\"学习能力\",\"description\":\"学习新知识的能力\",\"weight\":0.4}"
            + "]"
            + "}";

        mockMvc.perform(put("/api/portrait/template/{id}", templateId)
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestBody))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.dimensions", hasSize(2)));
    }

    // ==================== Helper Methods ====================

    private PortraitTemplateDTO createMockTemplateDTO(String templateId) {
        PortraitTemplateDTO dto = new PortraitTemplateDTO();
        dto.setId(templateId);
        dto.setTemplateName("技术岗位能力模板");
        dto.setDescription("用于评估技术岗位人才");
        dto.setEnterpriseId("ent001");
        dto.setCreatedBy("hr001");
        dto.setActive(true);
        dto.setAiSuggested(false);
        dto.setCreatedAt(LocalDateTime.now());
        dto.setUpdatedAt(LocalDateTime.now());
        
        List<TemplateDimension> dimensions = new ArrayList<>();
        dimensions.add(createDimension("tech", "技术能力", "技术掌握程度", 0.2));
        dimensions.add(createDimension("problem", "问题解决", "解决问题能力", 0.2));
        dimensions.add(createDimension("learning", "学习能力", "学习新知识的能力", 0.2));
        dimensions.add(createDimension("teamwork", "协作能力", "团队合作能力", 0.1));
        dimensions.add(createDimension("communication", "沟通能力", "表达和交流能力", 0.15));
        dimensions.add(createDimension("execution", "执行能力", "任务执行能力", 0.15));
        dto.setDimensions(dimensions);
        
        return dto;
    }

    private TemplateDimension createDimension(String code, String name, String description, double weight) {
        TemplateDimension dim = new TemplateDimension();
        dim.setCode(code);
        dim.setName(name);
        dim.setDescription(description);
        dim.setWeight(weight);
        return dim;
    }
}
